package pl.ptemich.nov2k13.engine;


import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;

import pl.ptemich.nov2k13.engine.configuration.GameConfiguration;
import pl.ptemich.tankwars.tools.HexTools;
import pl.ptemich.tankwars.tools.LoggingTools;

public class HexBoard {

  GameConfiguration gameConfig;

  private Image mapBackground;
  
  private float boardStartX;

  private float boardStartY;

  private Hex[][] hexes;

  private HexType hexType;
  
  /**
   * active / selected Hex
   */
  private Hex leftSelectedHex;
  
  private Hex rightSelectedHex;
  
  private List<Hex> rotations;
  
  private Hex hoverHex;

  
  public enum HexType {
    FLAT_ORIENTATION, POINTY_ORIENTATION;
  }
  
  public enum MouseButton {
    LEFT, MIDDLE, RIGHT;
  }

  public HexBoard(int startX, int startY, HexType hexType) throws SlickException {
    gameConfig =  GameConfiguration.getConfiguration();
    hexes = new AbstractHex[gameConfig.boardSizeX][gameConfig.boardSizeY];
    float h = AbstractHex.calculateH(gameConfig.hexSideLength);
    float r = AbstractHex.calculateR(gameConfig.hexSideLength);

    
    this.boardStartX = startX + h + gameConfig.hexSideLength / 2;
    this.boardStartY = startY + r;
    this.hexType = hexType;
    
    if (HexType.FLAT_ORIENTATION.equals(hexType)) {        
      for (int x = 0; x < gameConfig.boardSizeX; x++) {
        for (int y = 0; y < gameConfig.boardSizeY; y++) {
          if (x % 2 == 0) {
            hexes[x][y] = new FlatOrientationHex(gameConfig.hexSideLength, boardStartX + (h + gameConfig.hexSideLength) * x, boardStartY + 2 * r * y, x, y, h, r);
          } else {
            if (y < gameConfig.boardSizeY - 1) {
              hexes[x][y] = new FlatOrientationHex(gameConfig.hexSideLength, boardStartX + (h + gameConfig.hexSideLength) * x, boardStartY + 2 * r * y + r, x, y, h, r);
            }
          }
        }
      } 
    } else {
      for (int x = 0; x < gameConfig.boardSizeX; x++) {
        for (int y = 0; y < gameConfig.boardSizeY; y++) {
          if (y % 2 == 0) {
            hexes[x][y] = new PointyOrientationHex(gameConfig.hexSideLength, boardStartX + 2 * r * x, boardStartY + (h + gameConfig.hexSideLength) * y, x, y, h, r);
          } else {
            if (x < gameConfig.boardSizeX - 1) {
              hexes[x][y] = new PointyOrientationHex(gameConfig.hexSideLength, boardStartX + 2 * r * x + r, boardStartY + (h + gameConfig.hexSideLength) * y, x, y, h ,r);
            }
          }
        }
      }
    }
    
    // TODO crate image loader
    mapBackground = new Image("resources/images/" + gameConfig.backgroundImage);
    
    LoggingTools.debug("finished board init");
  }

  
  public void draw(Graphics graphics) {
    graphics.drawImage(mapBackground, boardStartX, boardStartY);
    
    for (int x = 0; x < gameConfig.boardSizeX; x++) {
      for (int y = 0; y < gameConfig.boardSizeY; y++) {
        if (hexes[x][y] != null) {
          hexes[x][y].draw(graphics);
        }
      }
    }

    if (hoverHex != null) {
      hoverHex.draw(graphics);
    }
    
    graphics.setColor(Color.white);
    if (leftSelectedHex != null) {
      graphics.drawString(leftSelectedHex.toString(), 20, 600);
    }
    
    if (rightSelectedHex != null) {
      graphics.drawString(rightSelectedHex.toString(), 520, 600);
    }    
    
    if (leftSelectedHex != null && rightSelectedHex != null) {
      int distance = HexTools.getDistance(leftSelectedHex.getOffsetCoordinate(), rightSelectedHex.getOffsetCoordinate());
      graphics.drawString("Distance: " + distance, 20, 580);
    }
  }

  
  
  public void mouseMove(int posX, int posY) {
    for (int x = 0; x < gameConfig.boardSizeX; x++) {
      for (int y = 0; y < gameConfig.boardSizeY; y++) {
        if (hexes[x][y] != null) {
          // check needed because last row is not doubled
          if (hexes[x][y].checkSelection(posX, posY)) {
            if (hoverHex != null) {
              hoverHex.getHexState().setHover(false);
            }
            hoverHex = hexes[x][y];
            hoverHex.getHexState().setHover(true);                    
          }
        }
      }
    }
  }  
  
  
  public void mouseClick(int posX, int posY, MouseButton button) {
    for (int x = 0; x < gameConfig.boardSizeX; x++) {
      for (int y = 0; y < gameConfig.boardSizeY; y++) {
        if (hexes[x][y] != null) {
          // check needed because last row is not doubled
          if (hexes[x][y].checkSelection(posX, posY)) {
            switch (button) {
              case LEFT: 
                if (leftSelectedHex != null) {
                  leftSelectedHex.getHexState().setLeftSelected(false);
                }
                leftSelectedHex = hexes[x][y];
                leftSelectedHex.getHexState().setLeftSelected(true);
                
                Set<Hex> ngl = getNeighbors(leftSelectedHex);
                for (Hex toSelect : ngl) {
                  toSelect.getHexState().setRightSelected(true);
                }                
                break;
                
              case RIGHT:
                if (rightSelectedHex != null) {
                  rightSelectedHex.getHexState().setRightSelected(false);
                }
                rightSelectedHex = hexes[x][y];
                rightSelectedHex.getHexState().setRightSelected(true);
                
                Set<Hex> ngr = getNeighbors(rightSelectedHex);
                for (Hex toSelect : ngr) {
                  toSelect.getHexState().setLeftSelected(true);
                }                
                break;                                          
              default:                
            }       
          }
          
          if (rightSelectedHex != null && leftSelectedHex != null) {
            
          }
          
          // middle button clears the selection
          if (MouseButton.MIDDLE.equals(button)) {
            hexes[x][y].getHexState().reset();
          }          
        }       
      }
    }
  }
  
  /**
   * TODO - must distinguish between flat and pointy HEX type
   * 
   * @param center
   * @return
   */
  public Set<Hex> getNeighbors(Hex center) {
    Set<Hex> result = new HashSet<Hex>();
    OffsetCooridinate offsetCooridinate = center.getOffsetCoordinate();
    
    AxialCoordinate axialCoordinate = offsetCooridinate.getAxialCoordinate();
    List<AxialCoordinate> neighbors = axialCoordinate.getNeighbors();
    
    OffsetCooridinate ngOffsetCoor;
    for (AxialCoordinate axCoordinate : neighbors) {
      ngOffsetCoor = axCoordinate.getOffsetCoordinate();
      addSingle(ngOffsetCoor.c, ngOffsetCoor.r, result);    
    }
    return result;
  }
  
  private void addSingle(int tabX, int tabY, Set<Hex> result) {
    if (tabX >= 0 && tabX < gameConfig.boardSizeX && tabY >= 0 && tabY < gameConfig.boardSizeY) {
      Hex tmp = hexes[tabX][tabY];
      if (tmp != null) {
        result.add(tmp);  
      }   
    }
  }
}
